#include <stdio.h>
#include <pthread.h>
#include <sys/time.h>
#include <sys/unistd.h>

void api_function() {
    // 创建互斥锁
    pthread_mutex_t mutex;

    // 初始化互斥锁
    pthread_mutex_init(&mutex, NULL);

    // 加锁
    pthread_mutex_lock(&mutex);

    // 尝试加锁
    pthread_mutex_trylock(&mutex);

    // 解锁
    pthread_mutex_unlock(&mutex);

    // 销毁互斥锁
    pthread_mutex_destroy(&mutex);
}

int count1 = 0;

void *callback1(void *arg) {
    for (int i = 0; i < 100; ++i) {
        int number = count1;
        number++;
        usleep(1000 * 20 * (*(int *) arg));
        count1 = number;
        usleep(1000 * 10 * (*(int *) arg));
    }
}

// 多线程不安全的情况
void thread_unsafe() {
    struct timeval start, end;
    gettimeofday(&start, NULL);

    pthread_t pid1, pid2, pid3;
    int value1 = 1;
    int value2 = 2;
    int value3 = 3;

    pthread_create(&pid1, NULL, callback1, &value1);
    pthread_create(&pid2, NULL, callback1, &value2);
    pthread_create(&pid3, NULL, callback1, &value3);

    pthread_join(pid1, NULL);
    pthread_join(pid2, NULL);
    pthread_join(pid3, NULL);

    printf("count1 = %d\n", count1);

    gettimeofday(&end, NULL);
    int use_time = 1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;

    printf("use time: %d\n", use_time);
}

int count2 = 0;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

// 多线程安全的情况
void *callback2(void *arg) {
    for (int i = 0; i < 100; ++i) {
        pthread_mutex_lock(&mutex);
        int number = count2;
        number++;
        usleep(1000 * 20 * (*(int *) arg));
        count2 = number;
        pthread_mutex_unlock(&mutex);
    }
}

void thread_safe() {
    struct timeval start, end;
    gettimeofday(&start, NULL);

    pthread_t pid1, pid2, pid3;
    int value1 = 1;
    int value2 = 2;
    int value3 = 3;

    pthread_create(&pid1, NULL, callback2, &value1);
    pthread_create(&pid2, NULL, callback2, &value2);
    pthread_create(&pid3, NULL, callback2, &value3);

    pthread_join(pid1, NULL);
    pthread_join(pid2, NULL);
    pthread_join(pid3, NULL);

    printf("count2 = %d\n", count2);

    pthread_mutex_destroy(&mutex);

    gettimeofday(&end, NULL);
    int use_time = 1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;

    printf("use time: %d\n", use_time);
}

pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;

void *callback3(void *arg) {
    printf("Thread %p 尝试获取资源1\n", pthread_self());
    pthread_mutex_lock(&mutex1);
    printf("Thread %p 获取了资源1\n", pthread_self());
    sleep(1);

    printf("Thread %p 尝试获取资源2\n", pthread_self());
    pthread_mutex_lock(&mutex2);
    printf("Thread %p 获取了资源2\n", pthread_self());
    sleep(1);

    printf("Thread %p 释放资源2\n", pthread_self());
    pthread_mutex_unlock(&mutex2);

    printf("Thread %p 释放资源1\n", pthread_self());
    pthread_mutex_unlock(&mutex1);
}

void *callback4(void *arg) {
    printf("Thread %p 尝试获取资源2\n", pthread_self());
    pthread_mutex_lock(&mutex2);
    printf("Thread %p 获取了资源2\n", pthread_self());
    sleep(1);

    printf("Thread %p 尝试获取资源1\n", pthread_self());
    pthread_mutex_lock(&mutex1);
    printf("Thread %p 获取了资源1\n", pthread_self());
    sleep(1);

    printf("Thread %p 释放资源1\n", pthread_self());
    pthread_mutex_unlock(&mutex1);

    printf("Thread %p 释放资源2\n", pthread_self());
    pthread_mutex_unlock(&mutex2);
}

void thread_dead_lock() {
    pthread_t pid1, pid2;

    pthread_create(&pid1, NULL, callback3, NULL);
    pthread_create(&pid2, NULL, callback4, NULL);

    // 线程 pid1 和 线程 pid2 都先获取到了资源, 然后尝试获取对方的资源导致死锁
    pthread_join(pid1, NULL);
    pthread_join(pid2, NULL);

    pthread_mutex_destroy(&mutex1);
    pthread_mutex_destroy(&mutex2);
}

int main(int argc, const char *argv[]) {
    thread_safe();

    thread_unsafe();

    thread_dead_lock();
}